﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Zhaoxi.Communication.Base;
using Zhaoxi.Configuration.Base;

namespace Zhaoxi.Communication.Protocols
{
    public class ModbusRTU : CommBase
    {
        Modbus.Device.ModbusSerialMaster slave;
        byte SlaveId = 1;

        public override void Connect(params CommParamEntity[] args)
        {
            string port_name = "COM1";
            var port = args.Where(p => p.name == "PortName")
                .FirstOrDefault();
            if (port != null) port_name = port.value;

            int baudRate = 9600;
            var p_baud = args.Where(p => p.name == "BaudRate")
                .FirstOrDefault();
            if (p_baud != null) baudRate = int.Parse(p_baud.value);

            var p_slave = args.Where(p => p.name == "SlaveId")
                .FirstOrDefault();
            if (p_slave != null) SlaveId = byte.Parse(p_slave.value);

            // 波特率
            // 数据位
            // 停止位
            // 校验位
            // 超时时间
            // 缓存大小

            SerialPort serialPort = new SerialPort();
            serialPort.PortName = port_name;
            serialPort.BaudRate = baudRate;
            serialPort.DataBits = 8;
            serialPort.StopBits = StopBits.One;
            //foreach (var arg in args)
            //{
            //    PropertyInfo pi = serialPort.GetType()
            //          .GetProperty(arg.name, BindingFlags.Instance | BindingFlags.Public);

            //    if (pi == null) continue;

            //    dynamic v = arg.value;

            //    pi.SetValue(serialPort, v);
            //}

            serialPort.Open();
            slave = Modbus.Device.ModbusSerialMaster.CreateRtu(serialPort);
        }

        public override void StartRead(params VariableEntity[] variables)
        {
            // 关于地址的接：
            // 串口通信出现一主多从的情况，串口对象复用
            // 目前采用的单地址访问，效率不高，办法就是将地址进行整合，批量读取
            // 不同变量不同类型的情况下，目前处理是可以的，需要进行类型判断，，然后进行存储区地址的长度以及数据类型转换
            foreach (var item in variables)
            {
                // 这里面涉及到Modbus相关的概念信息，自行了解，找助教老师拿下资料
                ushort[] values = slave.ReadHoldingRegisters(
                      SlaveId,
                      (ushort)(ushort.Parse(item.address) - 40001),
                      1);

                item.Value = values[0];

                if (item.condition == null) continue;
                // 做报警条件检查
                foreach (var c in item.condition)
                {
                    //if (c.@operator == ">")
                    //{
                    //    if (item.Value > c.value)
                    //        item.WarningMessage = c.message;
                    //}
                    string compare_str = item.Value + c.@operator + c.value.ToString();
                    // "111>100"
                    var state = new DataTable().Compute(compare_str, "");
                    if (Boolean.Parse(state.ToString()))
                    {
                        item.WarningMessage = c.message;
                    }
                }
            }
        }
    }
}
